#include<unistd.h>
#include<sys/wait.h>
#include "daemon.h"
#include "log.h"
#include "config.h"

namespace qtch {

static Logger::ptr logger = QTCH_LOG_NAME("system");

static ConfigVar<uint32_t>::ptr g_daemon_restart_interval 
    = qtch::Config::LookUp("daemon.restart_interval",(uint32_t)5,"daemon restart interval");

static pid_t s_pid = -1;

std::string ProcessInfo::toString(){
    std::stringstream ss;
    ss << "[ProcessInfo parentPid=" << parentPid << " parentStartTime=" << parentStartTime
       << " mainPid=" << mainPid << " mainStartTime=" << mainStartTime
       << " restartCount=" << restartCount;

    return ss.str();
}

int real_start(int argc,char** argv, std::function<int(int,char**)> main_cb){
    ProcessInfoMgr::GetInstance()->mainPid = getpid();
    ProcessInfoMgr::GetInstance()->mainStartTime = time(0);
    return main_cb(argc,argv);
}

void deamon_term(int sig){
    QTCH_LOG_INFO(logger) << "deamon received SIGTERM";
    if(s_pid <= 0){
        return;
    }
    kill(s_pid,SIGTERM);
}

int real_daemon(int argc,char** argv, std::function<int(int,char**)> main_cb){
    daemon(0,1);
    signal(SIGTERM,deamon_term);
    while(true){
        pid_t pid = fork();
        if(pid == 0){
            QTCH_LOG_INFO(logger) << "process start pid=" << getpid();
            return real_start(argc,argv,main_cb);
        } else if(pid < 0){
            QTCH_LOG_ERROR(logger) << "fork fail return=" << pid
                << " errno=" << errno << " errstr=" << strerror(errno);
            return -1;
        }
        int status = 0;
        s_pid = pid;
        waitpid(pid,&status,0);
        if(status){
            if(status==9){
                QTCH_LOG_ERROR(logger) << "child killed pid=" << pid;
            } else {
                QTCH_LOG_ERROR(logger) << "child crash pid=" << pid 
                    << " errno=" << errno << " strerr=" << strerror(errno) 
                    << " status=" << status;
            }
        }else {
            // 正常退出，表示任务全部完成了
            QTCH_LOG_INFO(logger) << "child finished pid=" << pid;
            break;
        }
        ProcessInfoMgr::GetInstance()->restartCount +=1;
        sleep(g_daemon_restart_interval->getValue());

    }
    return 0;
}


int start_daemon(int argc,char** argv
        , std::function<int(int,char**)> main_cb, bool is_deamon){
    ProcessInfoMgr::GetInstance()->parentPid = getpid();
    ProcessInfoMgr::GetInstance()->parentStartTime = time(0);
    if(!is_deamon){
        return real_start(argc,argv,main_cb);
    }
    else {
        return real_daemon(argc,argv,main_cb);
    }
}

}